using System;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using SharpPlanetsModel;
using GameModel;

namespace pocketSharpPlanets {
  public partial class pocketMainForm: Form {
    public pocketMainForm() {
      InitializeComponent();
    }

    private ArrayList planetList;
    private Rocket runningRocket;
    private LeftShip leftShip;
    private RightShip rightShip;

    private bool InsertingAngle; //true if inserting angle, false in inserting speed

    private bool LeftPlayersTurn; // true if it's player one's turn, false if it's player two's.

    /// <summary>
    /// on page load
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void Form1_Load(object sender, EventArgs e) {
      menuResetClick(sender, e);
    }

    /// <summary>
    /// exit from pocketSharpPlanets
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void menuCloseClick(object sender, EventArgs e) {
      Close();
    }

    /// <summary>
    /// ask for the angle value
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void menuAngleClick(object sender, EventArgs e) {
      CloseInsertPanel();
      InsertingAngle = true;
      SpeedAnglelabel.Text = "Angle";
      if (LeftPlayersTurn)
        speedAngleTextBox.Text = TurnPlayer1.Instance.Angle.ToString();
      else
        speedAngleTextBox.Text = TurnPlayer2.Instance.Angle.ToString();
      speedAngleTextBox.Focus();
      panel1.Visible = true;
    }

    /// <summary>
    /// ask for the speed value
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void menuSpeedClick(object sender, EventArgs e) {
      CloseInsertPanel();
      InsertingAngle = false;
      SpeedAnglelabel.Text = Configuration.speedLabel;

      if (LeftPlayersTurn)
        speedAngleTextBox.Text = TurnPlayer1.Instance.Speed.ToString();
      else
        speedAngleTextBox.Text = TurnPlayer2.Instance.Speed.ToString();

      speedAngleTextBox.Focus();
      panel1.Visible = true;
    }

    /// <summary>
    /// calculate and draw the track of the rocket
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void menuShootClick(object sender, EventArgs e) {
      CloseInsertPanel(); // for first.
      if (LeftPlayersTurn) {
        // player 1 shoots
        ExecuteShoot(leftShip.CenterPosition, TurnPlayer1.Instance.Speed, TurnPlayer1.Instance.Angle);
        // turn change
        statusLabel.Text = TurnPlayer2.Instance.StatusText;
        statusLabel.Invalidate();
        statusLabel.Refresh();
        LeftPlayersTurn = false;
      }
      else {
        // player 2 shoots
        ExecuteShoot(rightShip.CenterPosition, TurnPlayer2.Instance.Speed, TurnPlayer2.Instance.Angle);
        // turn change
        statusLabel.Text = TurnPlayer1.Instance.StatusText;
        statusLabel.Invalidate();
        statusLabel.Refresh();
        LeftPlayersTurn = true;
      }

    }

    /// <summary>
    /// reload the battle _Angle
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void menuResetClick(object sender, EventArgs e) {
      runningRocket = null;
      if (planetList != null) {
        planetList.Clear();
      }
      else {
        planetList = new ArrayList();
      }

      //create list of random numbers for radius
      int[] rndradius = new int[3];
      Random randomNumber = new Random();
      rndradius[0] = randomNumber.Next(Configuration.rangeRadius0_low, Configuration.rangeRadius0_high);
      rndradius[1] = randomNumber.Next(Configuration.rangeRadius1_low, Configuration.rangeRadius1_high);
      rndradius[2] = randomNumber.Next(Configuration.rangeRadius2_low, Configuration.rangeRadius2_high);

      //create list of random numbers for yPosition
      int[] rndyPosition = new int[5];
      Random randomNumberY = new Random();
      rndyPosition[0] = randomNumberY.Next(Configuration.rangePos0_low, Configuration.rangePos0_high);
      rndyPosition[1] = randomNumberY.Next(Configuration.rangePos1_low, Configuration.rangePos1_high);
      rndyPosition[2] = randomNumberY.Next(Configuration.rangePos2_low, Configuration.rangePos2_high);
      rndyPosition[3] = randomNumberY.Next(Configuration.rangePos3_low, Configuration.rangePos3_high);
      rndyPosition[4] = randomNumberY.Next(Configuration.rangePos4_low, Configuration.rangePos4_high);

      // create one by one, each planet
      Jupiter J = new Jupiter(rndradius[0]);
      J.CenterPosition.setXAbs(Configuration.xPos0);
      J.CenterPosition.setYAbs(rndyPosition[0]);
      Mercury M = new Mercury(rndradius[1]);
      M.CenterPosition.setXAbs(Configuration.xPos1);
      M.CenterPosition.setYAbs(rndyPosition[1]);
      Venus V = new Venus(rndradius[2]);
      V.CenterPosition.setXAbs(Configuration.xPos2);
      V.CenterPosition.setYAbs(rndyPosition[2]);
      //adding objects to list
      planetList.Add(J);
      planetList.Add(M);
      planetList.Add(V);

      if (rightShip != null) {
        rightShip.CenterPosition.setYAbs(rndyPosition[3]);
      }
      else {
        rightShip = new RightShip(new Position(Configuration.xRightShipPos, rndyPosition[3]));
      }

      if (leftShip != null) {
        leftShip.CenterPosition.setYAbs(rndyPosition[4]);
      }
      else {
        leftShip = new LeftShip(new Position(Configuration.xLeftShipPos, rndyPosition[4]));
      }
      backgroundImage.Invalidate();
      backgroundImage.Refresh();
      // this.Invalidate();
      // this.Refresh();

      LeftPlayersTurn = true;
    }

    private void pictureBox1_Paint(object sender, PaintEventArgs e) {
      foreach (MassiveSpaceObject iteratore in planetList) {
        iteratore.Paint(e.Graphics);
      }
      if (rightShip != null)
        rightShip.Paint(e.Graphics);
      if (leftShip != null)
        leftShip.Paint(e.Graphics);
      if (runningRocket != null)
        runningRocket.Paint(e.Graphics);
      
    }

    private void pocketMainForm_KeyDown(object sender, KeyEventArgs e) {
      if ((e.KeyCode == System.Windows.Forms.Keys.F1)) {
        // Soft Key 1
        // Not handled when menu is present.
      }
      if ((e.KeyCode == System.Windows.Forms.Keys.F2)) {
        // Soft Key 2
        // Not handled when menu is present.
      }
      if ((e.KeyCode == System.Windows.Forms.Keys.Up)) {
        // Up
        if (panel1.Visible) {
          int value = Convert.ToInt16(speedAngleTextBox.Text);
          if (InsertingAngle) {
            if (value == Configuration.maxAngleAcceptedValue)
              value = 1;
            else {
              value++;
            }
            speedAngleTextBox.Text = value.ToString();
          }

          else {
            if (value < Configuration.maxSpeedAcceptedValue) {
              value++;
              speedAngleTextBox.Text = value.ToString();
            }
          }
        }
      }
      if ((e.KeyCode == System.Windows.Forms.Keys.Right)) {
        // Right
      }
      if ((e.KeyCode == System.Windows.Forms.Keys.Down)) {
        //Down
        if (panel1.Visible) {
          int value = Convert.ToInt16(speedAngleTextBox.Text);
          if (value > 0) {
            value--;
            speedAngleTextBox.Text = value.ToString();
          }
          else if (InsertingAngle) {
            value = Configuration.maxAngleAcceptedValue - 1;
            speedAngleTextBox.Text = value.ToString();
          }
        }
      }
      if ((e.KeyCode == System.Windows.Forms.Keys.Left)) {
        // Left
      }
      if ((e.KeyCode == System.Windows.Forms.Keys.Enter)) {
        // Enter
        if (panel1.Visible)
          CloseInsertPanel();
      }
      if ((e.KeyCode == System.Windows.Forms.Keys.D0)) {
        // 0
      }

    }

    private void CloseInsertPanel() {
      if (panel1.Visible) {
        if (InsertingAngle) {
          if (LeftPlayersTurn)
            TurnPlayer1.Instance.Angle = Convert.ToInt16(speedAngleTextBox.Text);
          else
            TurnPlayer2.Instance.Angle = Convert.ToInt16(speedAngleTextBox.Text);
        }
        else {
          if (LeftPlayersTurn)
            TurnPlayer1.Instance.Speed = Convert.ToInt16(speedAngleTextBox.Text);
          else
            TurnPlayer2.Instance.Speed = Convert.ToInt16(speedAngleTextBox.Text);
        }
        panel1.Visible = false;
      }
    }

    public void ExecuteShoot(Position startPosition, int startSpeed, int startAngle) {
      double realspeed = startSpeed;
      double radangle = Utilities.ConvertAngleToRad(startAngle);
      int i, isf, safethreshold;
      double timetopaint = 1.0 / Configuration.globalScaleFactor;
      runningRocket = new Rocket(startPosition);
      double x_new, y_new, x_old, y_old, aumentx, aumenty, speed_x, speed_y;
      double x_now = startPosition.getXAbs();
      double y_now = startPosition.getYAbs();
      Double vel_x = realspeed * Math.Cos(radangle);
      Double vel_y = realspeed * Math.Sin(radangle);
      x_old = x_now + vel_x;
      y_old = y_now + vel_y;
      speed_x = vel_x;
      speed_y = vel_y;
      i = 0;
      isf = 0;
      safethreshold = (int)(Configuration.shipCollisionThreshold / (double)realspeed);
      while (mustCalculateNextShootStep(i, safethreshold, x_old, y_old)) {
        Position currentPosition = new Position((int)x_old, (int)y_old);
        aumentx = speed_x;
        aumenty = speed_y;
        foreach (Planet p in planetList) {
          aumentx += p.gravityEffectX(currentPosition);
          aumenty += p.gravityEffectY(currentPosition);
        }
        x_new = x_old + aumentx;
        y_new = y_old + aumenty;
        speed_x = x_new - x_old;
        speed_y = y_new - y_old;

        if (isf >= timetopaint) {
          runningRocket.AddPosition(new Position((int)x_new, (int)y_new));
          Rectangle rectToRefresh = new Rectangle((int)(Configuration.globalScaleFactor * x_new), (int)(Configuration.globalScaleFactor * y_new), 2, 2);
          backgroundImage.Invalidate(rectToRefresh);
          Application.DoEvents();
          isf = 0;
        }
        x_old = x_new;
        y_old = y_new;
        i++;
        isf++;
      }
      Position lastPosition = new Position((int)x_old, (int)y_old);
      if (leftShip.IsCollision(lastPosition)) {
        statusLabel.Text = Configuration.blueShipDestroyedMessage;
      }
      else if (rightShip.IsCollision(lastPosition)) {
        statusLabel.Text = Configuration.redShipDestroyedMessage;
      }
      else if (i >= Configuration.numberOfIterationPerShoot) {
      }
      else {
        statusLabel.Text = Configuration.hitAPlanetMessage;
      }
      backgroundImage.Invalidate();
      backgroundImage.Refresh();
    }

    /// <summary>
    /// draws the shot
    /// </summary>
    /// <param name="LeftTurn">true if it is left player's turn, false if right player's one</param>
    /// <param name="SpeedValue">intial value of the rocket's speed</param>
    /// <param name="AngleValue">initial value in degree of the rocket direction</param>
    /// <returns>true if a ship is hit, false otherwise</returns>
    public bool DoShoot(bool LeftTurn, float SpeedValue, float AngleValue) {
      double realspeed, radangle;
      realspeed = SpeedValue;
      radangle = Utilities.ConvertAngleToRad(AngleValue);

      int i, isf, safethreshold;
      //double GlobalScaleFactor = Configuration.fieldWidthInPixels / Configuration.fieldWith;
      double timetopaint = 1.0 / Configuration.globalScaleFactor;
      Boolean Gotcha = false;
      //////    Shooting = true;
      //////    LeftPlayer = LeftTurn;
      //////    //System.out.println("sono in DoShoot");
      //////    ShipOne.setSelected(false);
      //////    ShipTwo.setSelected(false);
      if (LeftTurn) {
        runningRocket = new Rocket(leftShip.CenterPosition);
      }
      else {
        runningRocket = new Rocket(rightShip.CenterPosition);
      }

      //////    RocketTrack.clean();
      //////    MyStatusLabel = "";
      //////    //this.repaint();
      //////    this.paintImmediately(0, 0, this.getWidth(), this.getHeight());
      double x_new, y_new, x_old, y_old, aumentx, aumenty, speed_x, speed_y;
      double x_now, y_now;
      //////    // disegnamo lo Shoot
      if (LeftTurn) {
        //RocketTrack.SetStartingPoint(ShipOne.getCenterX(), ShipOne.getCenterY());
        x_now = leftShip.CenterPosition.getXAbs();//ShipOne.getCenterX();
        y_now = leftShip.CenterPosition.getYAbs();// ShipOne.getCenterY();
      }
      else {
        //RocketTrack.SetStartingPoint(ShipTwo.getCenterX(), ShipTwo.getCenterY());
        x_now = rightShip.CenterPosition.getXAbs();//x_now = ShipTwo.getCenterX();
        y_now = rightShip.CenterPosition.getYAbs();//ShipTwo.getCenterY();
      }

      Double vel_x = realspeed * Math.Cos(radangle);
      Double vel_y = realspeed * Math.Sin(radangle);
      x_old = x_now + vel_x;
      y_old = y_now + vel_y;
      speed_x = vel_x;
      speed_y = vel_y;
      i = 0;
      isf = 0;
      //int MaxIterations = Configuration.numberOfIterationPerShoot;
      safethreshold = (int)(Configuration.shipCollisionThreshold / (double)realspeed);
      while (mustCalculateNextShootStep(i, safethreshold, x_old, y_old)) {
        Position currentPosition = new Position((int)x_old, (int)y_old);
        aumentx = speed_x;
        //  + GravityConstant
        //  * (Jupiter.gravityEffectX(x_old, y_old) +
        //     Mercury.gravityEffectX(x_old,
        //                 y_old) + Venus.gravityEffectX(x_old,
        //                                y_old));
        aumenty = speed_y;
        foreach (Planet p in planetList) {
          aumentx += p.gravityEffectX(currentPosition);
          aumenty += p.gravityEffectY(currentPosition);
        }
        //+ GravityConstant * (Jupiter.gravityEffectY(x_old, y_old) +
        //                   Mercury.gravityEffectY(x_old,
        //                               y_old) +
        //                   Venus.gravityEffectY(x_old, y_old));
        x_new = x_old + aumentx;
        y_new = y_old + aumenty;
        speed_x = x_new - x_old;
        speed_y = y_new - y_old;

        if (isf >= timetopaint) {
          runningRocket.AddPosition(new Position((int)x_new, (int)y_new));
          //if (((int)(GlobalScaleFactor * x_new) < Configuration.fieldWidthInPixels)
          //    && (GlobalScaleFactor * y_new < 220))
          Rectangle rectToRefresh = new Rectangle((int)(Configuration.globalScaleFactor * x_new), (int)(Configuration.globalScaleFactor * y_new), 2, 2);
          backgroundImage.Invalidate();
          //backgroundImage.Refresh();
          //this.Invalidate();
          ////((int)(GlobalScaleFactor * x_new - 2),
          ////               (int)(GlobalScaleFactor * y_new - 2), 4,
          ////               4);
          isf = 0;
        }
        x_old = x_new;
        y_old = y_new;
        i++;
        isf++;
      }
      //////    if (TwoPlayers)
      //////    {
      //////        if (LeftTurn)
      //////            ShipTwo.setSelected(true);
      //////        else
      //////            ShipOne.setSelected(true);
      //////    }
      Position lastPosition = new Position((int)x_old, (int)y_old);
      if (leftShip.IsCollision(lastPosition)) {

        //////        //Shooting=false;
        statusLabel.Text = Configuration.blueShipDestroyedMessage;
        //////        ShipOne.kaboom();
        //////        this.paintImmediately((int)(GlobalScaleFactor * x_old - 30),
        //////                       (int)(GlobalScaleFactor * y_old - 30), 60,
        //////                       60);

        //////        try
        //////        {
        //////            suona(this.ExplosionSound);
        //////        }
        //////        catch (IOException e)
        //////        {
        //////            // TODO Auto-generated catch block
        //////            e.printStackTrace();
        //////        }
        //////        Gotcha = true;
      }
      else if (rightShip.IsCollision(lastPosition)) {

        //////        ShipTwo.kaboom();
        statusLabel.Text = Configuration.redShipDestroyedMessage;
        //////        this.paintImmediately((int)(GlobalScaleFactor * x_old - 30),
        //////                       (int)(GlobalScaleFactor * y_old - 30), 60,
        //////                       60);

        //////        try
        //////        {
        //////            suona(this.ExplosionSound);
        //////        }
        //////        catch (IOException e)
        //////        {
        //////            // TODO Auto-generated catch block
        //////            e.printStackTrace();
        //////        }

        //////        Gotcha = true;
      }
      else if (i >= Configuration.numberOfIterationPerShoot) {
        //////        /*
        //////           try {
        //////           suona(this.WooshSound);
        //////           } catch (IOException e) {

        //////           e.printStackTrace();
        //////           } */
        //////        MyStatusLabel = "Rocket lost in space.";

      }
      else {
        // colpito un pianeta
        ////try
        ////{
        ////    //suona(PlanetCollisionSound);
        ////}
        ////catch (IOException e)
        ////{
        ////    // TODO Auto-generated catch block
        ////    e.printStackTrace();
        ////}
        //Shooting=false;
        statusLabel.Text = Configuration.hitAPlanetMessage;
      }
      backgroundImage.Invalidate();
      backgroundImage.Refresh();
      return Gotcha;
    }

    
    /// <summary>
    ///
    /// </summary>
    /// <param name="i"></param>
    /// <param name="safethreshold"></param>
    /// <param name="x_old"></param>
    /// <param name="y_old"></param>
    /// <param name="MaxIterations"></param>
    /// <returns></returns>
    private bool mustCalculateNextShootStep(int i, int safethreshold, double x_old, double y_old) {
      Position currentPosition = new Position((int)x_old, (int)y_old);
      return ((i < Configuration.numberOfIterationPerShoot) && !(shootCollidesWithSomePlanet(currentPosition))
             && ((i < safethreshold) || !(shootCollidesWithOneShip(currentPosition))));
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="shootPosition"></param>
    /// <returns></returns>
    private bool shootCollidesWithOneShip(Position shootPosition) {
      return leftShip.Collide(shootPosition)
        || rightShip.Collide(shootPosition);
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="shootPosition"></param>
    /// <returns></returns>
    private bool shootCollidesWithSomePlanet(Position shootPosition) {
      return ((Planet)(planetList[0])).Collide(shootPosition)
        || ((Planet)(planetList[1])).Collide(shootPosition)
        || ((Planet)(planetList[2])).Collide(shootPosition);
    }
  }
}
